package com.botann.projects.utils;

import com.botann.projects.base.SGRuntimeException;
import com.botann.projects.constants.Constant;
import com.botann.projects.annotations.Excel;
import com.botann.projects.base.SGRuntimeException;
import com.botann.projects.constants.Constant;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellUtil;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

/**
 * 利用开源组件POI3.0.2动态导出EXCEL文档 转载时请保留以下信息，注明出处！
 * 
 * @author pengrongchao
 * @version v1.0
 * @param <T>
 *            应用泛型，代表任意一个符合javabean风格的类
 *            注意这里为了简单起见，boolean型的属性xxx的get器方式为getXxx(),而不是isXxx()
 *            byte[]表jpg格式的图片数据
 */

public class ExportExcel<T>{

	/**
	 * 这是一个通用的方法，利用了JAVA的反射机制，
	 * 可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 *
	 * @param dataSet models Collection<T>
	 */
	public SXSSFSheet exportSheet(List dataSet, SXSSFSheet sheet) throws Exception{
		boolean createdHeader = false;
		int index = 0;
		if (sheet == null) {
			XSSFWorkbook workbook = new XSSFWorkbook();
			SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(workbook, 100);
			sheet= sxssfWorkbook.createSheet();
		} else {
			createdHeader = true;
			index = sheet.getLastRowNum();
		}
		Iterator<T> it = dataSet.iterator();
		List<String> headers = new ArrayList<>();
		List<Integer> indexes = new ArrayList<>();
		while (it.hasNext()) {
			index++;
			Row row = sheet.createRow(index);
			T t = it.next();
			// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值
			Field[] fields = t.getClass().getDeclaredFields();
			short col = 0;
			for (short i = 0; i < fields.length; i++) {
				Field field = fields[i];
				Excel annotationExcel = field.getAnnotation(Excel.class);
				if (annotationExcel==null) continue;
				if (index == 1) { // 获取header
					headers.add(annotationExcel.value());
					indexes.add(annotationExcel.index()>-1?annotationExcel.index():col);
				}
				/**
				 * 写header,
				 * 为什么非得第2行时写表头,因为每100行写入disk, 最后再写,可能表头位置已经存入disk不能写入
				 */
				else if (index == 2 && !createdHeader) {
					Row headerRow = sheet.createRow(0);
					for (short k = 0; k < headers.size(); k++) {
						CellUtil.createCell(headerRow, indexes.get(k), headers.get(k));
					}
					createdHeader = true;
				}
				String cellValue = resolveExcelValue(field,getFieldValue(field,t),annotationExcel);
				CellUtil.createCell(row, annotationExcel.index()>-1?annotationExcel.index():col, cellValue);
				col++;
			}
		}
		/**
		 * 防止只有1行,所以重写表头
		 * 在第2行已经写过表头, 不能放在这里最后写表头, 因为可能前100行已经写入disk,这里处理仅仅是防止只有一行,没有第二行数据而失去表头
		 */
		if (!createdHeader) {
			Row headerRow = sheet.createRow(0);
			for (short k = 0; k < headers.size(); k++) {
				CellUtil.createCell(headerRow, indexes.get(k), headers.get(k));
			}
			createdHeader = true;
		}
		return sheet;
	}


	public void exportExcel(SXSSFSheet sheet, HttpServletResponse response, String fileName)  throws Exception{
		sheet.trackAllColumnsForAutoSizing();
		int columnNum = 100;
		SXSSFRow row = sheet.getRow(sheet.getLastRowNum());
		if (row != null) columnNum = row.getLastCellNum();
		for (int i=0;i<columnNum;i++) {
			sheet.autoSizeColumn(i);
		}
		response.setHeader("content-disposition","attachment;filename="+ URLEncoder.encode(
				fileName+"_"+DateUtils.date2String(new Date(),"yyyy-MM-dd HH_mm_ss")+".xlsx", "UTF-8"));
//		response.setHeader("content-type","application/x-msdownload");
//		response.setHeader("content-type","application/vnd.ms-excel;charset=UTF-8");
		OutputStream out = response.getOutputStream();
		sheet.getWorkbook().write(out);
		out.close();
	}

	public void exportExcel(List dataSet, HttpServletResponse response, String fileName) throws Exception{
		SXSSFSheet sheet = exportSheet(dataSet,null);
		exportExcel(sheet,response,fileName);
	}

	public static Object getFieldValue(Field field, Object t) throws Exception {
		String fieldName = field.getName();
		String getMethodName = "get"
				+ fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1);
		Class tCls = t.getClass();
//				Method getMethod = tCls.getMethod(getMethodName,
//						clazz);
//				Object value = getMethod.invoke(t,object);
		Method getMethod = tCls.getMethod(getMethodName,
				null);
		return getMethod.invoke(t,null);
	}

	public static String resolveExcelValue(Field field, Object value,Excel annotationExcel) {
		String cellValue = null;
		if (annotationExcel.values().equals(Constant.kExcelDate)) {
			if (value != null) cellValue = DateUtils.date2String((Date) value,annotationExcel.resolveValues());
		} else {
			if (value == null) value = "";
			if (annotationExcel.values().isEmpty()) {
				cellValue = String.valueOf(value);
			} else { // 枚举类型解析
				String [] strings = annotationExcel.values().split(",");
				String [] outStrings = annotationExcel.resolveValues().split(",");
				if (strings.length != outStrings.length) throw new SGRuntimeException("转Excel解析错误:" + field.getName());
				cellValue = String.valueOf(value);
				for (short j=0;j<strings.length;j++) {
					if (cellValue.equals(strings[j])) {
						cellValue = outStrings[j];
						break;
					}
				}
			}
		}
		if (cellValue == null) cellValue = "";
		return cellValue;
	}


}
